/*******************************************************************************
 * Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
 * Copyright (c) 2011- kotemaru@kotemaru.org
 ******************************************************************************/
package org.kotemaru.gae.dstool.client;

import java.net.*;
import java.io.*;
import java.util.*;
import java.util.*;
import org.kotemaru.util.json.*;
import org.kotemaru.util.*;

public class EntityUploader {
	private String baseUrl;
	private HttpURLConnection conn;
	private OutputStream outStream;
	private int limit = 100;
	private GaeOAuthClient client;

	public EntityUploader(GaeOAuthClient client, String url, String kind) {
		this.client = client;
		this.baseUrl = url + "?kind="+kind;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

	public void upload(Reader reader) throws Exception  {
		JSONParser parser = new JSONParser(reader);

		List<Map> list = readData(parser, limit);
		while (list.size()>0) {
			for (int i=0; i<list.size(); i++) {
				uploadOneEntity(list.get(i));
			}
			int count = close();
			if (count < list.size()) {
				for (int i=0; i<count; i++) list.remove(0);
				continue;
			}
			list = readData(parser, limit);
		}

		close();
	}

	private List<Map> readData(JSONParser parser, int limit) {
		List<Map> list = new ArrayList(limit);

		int tkn = parser.nextToken();
		if (tkn != '{') tkn = parser.nextToken();
		while (tkn == '{') {
			Map map = parser.pObject(tkn, null);
			list.add(map);
			if (list.size()>=limit) break;
			tkn = parser.nextToken();
			if (tkn != '{') tkn = parser.nextToken();
		}
		return list;
	}


	private void uploadOneEntity(Map entity) throws Exception {
		OutputStream out = this.getOutputStream();
		JSONSerializer seri = new JSONSerializer(out);
		seri.sObject(entity);
		out.write('\n');
		out.flush();
	}

	private OutputStream getOutputStream()  throws Exception {
		if (outStream != null) return outStream;

		if (conn == null) open(baseUrl+"&limit="+limit);
		outStream = conn.getOutputStream();
		if (!(outStream instanceof BufferedOutputStream)) {
			outStream = new BufferedOutputStream(outStream, 1024);
		}
		return outStream; 
	}
	private void open(String loc)  throws Exception {
		conn = (HttpURLConnection) new URL(loc).openConnection();
		conn.setFollowRedirects(false); 
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-type", "text/plain; charset=UTF-8");

		String oauth = client.getOAuthHeader("POST", loc);
System.out.println("===>"+oauth);
		conn.setRequestProperty("Authorization", oauth);

		conn.setDoOutput(true);
	}

	public int close()  throws Exception {
		if (conn == null) return 0;

		int count = 0;
		int status = conn.getResponseCode();
		System.err.println("Status: "+status);
		if (status == 200) {
			String res = IOUtil.streamToString(conn.getInputStream(),"UTF-8");
			count = Integer.parseInt(res);
			System.out.println("upload "+res+" entities.");
		} else {
			System.err.println(IOUtil.streamToString(conn.getErrorStream(),"UTF-8"));
		}
		conn.disconnect();
		conn = null;
		outStream = null;
		return count;
	}

}
